Skip to content

test: add Vitest unit tests and Playwright E2E with MinIO S3 mock#20

Merged
sboh1214 merged 6 commits into
mainfrom
feat@add-tests
May 12, 2026
Merged

test: add Vitest unit tests and Playwright E2E with MinIO S3 mock#20
sboh1214 merged 6 commits into
mainfrom
feat@add-tests

Conversation

@sboh1214
Copy link
Copy Markdown
Contributor

배경

현재 레포에는 자동화 테스트가 없어 리팩토링이나 기능 추가 시 회귀를 잡기 어려웠습니다. 이 PR은 세 레이어의 테스트 인프라를 추가합니다.

  • 단위/컴포넌트/통합: Vitest + React Testing Library + jsdom
  • E2E: Playwright + Chromium + docker-compose 기반 Postgres/MinIO
  • 커버리지: V8 coverage, 95% 기준 (codecov.yml)

변경 사항

Vitest 테스트 스위트 (75da9e9)

  • 51개 파일 / 691개 테스트
  • 대상: src/utils/* 전체, 주요 컴포넌트, (stdev) 페이지들, (cms)/admin 액션, Prisma/better-auth 통합
  • S3 호출은 aws-sdk-client-mock으로 모킹, 파일 업로드는 node:bufferFile 폴리필로 실제 바이트 검증
  • 커버리지 타겟 95% 라인

Playwright E2E (995f778, 이 PR 후반부에서 추가 정비)

  • 4개 spec: admin-signin, admin-crud-smoke, public-navigation, public-responsive
  • docker-compose.test.yml의 격리된 Postgres에 Prisma migration + seed 후 실행
  • src/e2e/fixtures/{db,auth}.ts에 DB 상태 관리 + better-auth 세션 헬퍼

초기 구성 이슈 정리 (8e80305)

커밋 534f216의 PayloadCMS 정리에서 이미 이름이 바뀐 env var(PAYLOAD_S3_TARGET_BUCKETS3_BUCKET)과 삭제된 env var(PAYLOAD_S3_BASE_URL)을 참조하던 stale 테스트 4건을 현재 컨벤션으로 정합.

E2E 파이프라인 재정비 (53c7767)

문제: 기존 pnpm test:e2ecp .env.example .env를 무조건 실행해 개발자 로컬 .envpostgres://user:password@host:5432/schema placeholder로 덮어썼고, 그 결과 Prisma migration이 존재하지 않는 DB에 붙으려다 실패했습니다. 사실상 작동하지 않는 상태였습니다.

해결:

  • .env.test 도입: e2e 전용 env를 dummy 값으로 커밋. Playwright/prepare/seed 스크립트 모두 이 파일만 명시적으로 로드 → 개발자 로컬 .env를 건드리지 않음. playwright.config.ts의 webServer env: 블록은 중복이므로 제거 (Playwright가 자동으로 process.env를 상속).
  • MinIO S3 mock: docker-compose.test.yml에 MinIO 사이드카 추가. entrypoint 오버라이드로 mkdir -p /data/stdev-kr && exec minio server /data 한 줄로 버킷 초기화(별도 init 사이드카 없음). src/utils/s3.ts에 AWS SDK 공식 env var AWS_ENDPOINT_URL_S3 핸들링 추가 (+ forcePathStyle: true). 프로덕션은 이 변수가 없으므로 동작 변화 없음.
  • Scripts 재배치: scripts/src/scripts/로 이동 (git rename으로 이력 보존). src/utils/(런타임 헬퍼)와 혼동되지 않도록 src/tests/, src/e2e/와 평행한 형제 디렉토리 구조.
  • prepare-playwright-e2e.mjs: 커스텀 pg_isready 폴링 루프 제거, docker compose up -d --wait로 postgres + minio healthcheck 기반 대기.

부가 정리

  • package.json의 stale migrate:payload 스크립트 삭제 — 참조 파일(scripts/migrate-payload-to-prisma.ts)은 534f216에서 이미 삭제됨.
  • README.md의 E2E 섹션에 MinIO 의존성 명시.
  • codecov.yml의 coverage ignore 경로 갱신 (scripts/**/*src/scripts/**/*).

검증

  • pnpm test: 51 files / 691 tests PASS
  • pnpm lint: clean
  • pnpm e2e:prepare: 전체 파이프라인(compose up → migrate → seed) 실환경에서 성공 확인
  • MinIO smoke test: @aws-sdk/client-s3로 PUT/GET/LIST 왕복 성공
  • LSP diagnostics: 변경된 모든 파일 clean

실행 방법

```bash
pnpm install
pnpm test # 단위/컴포넌트
pnpm test:coverage # 커버리지
pnpm test:e2e:install # 최초 1회, Chromium 설치
pnpm test:e2e # E2E (Docker 필요)
```

참고

  • dotenv는 override 기본값이 false라 CI가 export한 secret이 .env.test 값보다 우선합니다 (결정성 + 유연성).
  • MinIO 컨테이너는 tmpfs: /data로 데이터를 저장하지 않아 테스트 간 격리가 자동 보장됩니다.

sboh1214 added 4 commits May 12, 2026 15:42
Add a Playwright E2E preparation flow that starts the test Postgres container, applies Prisma migrations, and seeds dummy CMS data before tests.

Update CI to run the E2E job with the same docker-compose based flow, and document the test commands in README.md.
Commit 534f216 renamed `PAYLOAD_S3_TARGET_BUCKET` -> `S3_BUCKET` and
removed `PAYLOAD_S3_BASE_URL` across source, but tests added afterward on
this branch still referenced the old names, causing 4 failures in
`s3.test.ts` and `public-url.test.ts`.

- Rename `PAYLOAD_S3_TARGET_BUCKET` -> `S3_BUCKET` stubs in `s3.test.ts`
  and `public-url.test.ts` so module-time env reads actually pick up the
  custom bucket and region.
- Drop the two `PAYLOAD_S3_BASE_URL` tests; that env var was deliberately
  deleted (not renamed) and re-introducing it would contradict the
  refactor. Add a symmetric negative case against `S3_BUCKET` instead.
- Rename `PAYLOAD_S3_TARGET_BUCKET` -> `S3_BUCKET` in `src/tests/setup.ts`
  and `playwright.config.ts` so Vitest global setup and the Playwright
  web server actually propagate the bucket name to runtime code.
기존 `pnpm test:e2e`는 `cp .env.example .env`가 무조건 실행돼 개발자의
로컬 `.env`를 placeholder(`postgres://user:password@host:5432/schema`)로
덮어썼고, 그 결과 migrate/seed가 존재하지 않는 DB로 붙으려 실패하고
있었습니다. 이 커밋은 e2e 파이프라인 전체를 재정비합니다.

- `.env.test` 도입 (dummy 값만 담겨있어 커밋). Playwright, prepare,
  seed 스크립트 모두 이 파일만 명시적으로 로드하므로 개발자 로컬
  `.env`를 건드리지 않습니다. `.gitignore`에 `!.env.test` 예외 추가.
- `playwright.config.ts`의 webServer `env:` 블록 제거 — Playwright가
  자동으로 `process.env`를 상속하므로 중복.
- `package.json`의 `test:e2e`, `test:e2e:ui`에서 `cp .env.example .env`
  제거.
- `docker-compose.test.yml`에 MinIO 서비스 추가. entrypoint를 override해
  `mkdir -p /data/stdev-kr && exec minio server /data`로 버킷 디렉토리를
  먼저 만든 뒤 서버를 기동 — 별도 init 사이드카 없이 한 서비스로 해결.
- `src/utils/s3.ts`: AWS SDK 공식 env var인 `AWS_ENDPOINT_URL_S3`가
  세팅되면 `endpoint + forcePathStyle: true`를 `S3Client`에 주입.
  프로덕션에는 이 변수를 세팅하지 않으므로 동작 변화 없음. `.env.test`에
  `AWS_ENDPOINT_URL_S3=http://127.0.0.1:9000` 포함.
- `scripts/` → `src/scripts/`로 이동 (git rename으로 이력 보존).
  `src/utils/`(런타임 헬퍼)와 혼동되지 않도록 `src/tests/`, `src/e2e/`
  와 평행한 형제 디렉토리로 배치.
- `package.json`의 stale `migrate:payload` 엔트리 제거 — 참조하던 파일
  `scripts/migrate-payload-to-prisma.ts`는 이미 커밋 534f216에서
  PayloadCMS 정리와 함께 삭제됨.
- `codecov.yml`의 ignore 경로를 `src/scripts/**/*`로 갱신.
- `src/scripts/prepare-playwright-e2e.mjs`: 커스텀 pg_isready 폴링 루프
  제거, `docker compose up -d --wait`로 postgres와 minio 둘 다
  healthcheck 기반 대기.
- README의 E2E 섹션에 MinIO 의존성 문구 추가.
@sboh1214 sboh1214 self-assigned this May 12, 2026
@sboh1214 sboh1214 added the test label May 12, 2026
@sboh1214
Copy link
Copy Markdown
Contributor Author

@codex review

직전 커밋 53c7767에서 `scripts/` → `src/scripts/`로 이동하면서 Vitest의
`coverage.include: ['src/**/*.{ts,tsx}']` glob이 `src/scripts/seed-playwright-e2e.ts`
(166 lines, 0% coverage)를 새로 포획해 전체 커버리지가 93.63%로 떨어졌습니다.
`codecov.yml`의 ignore 경로는 이동과 함께 갱신됐으나 `vitest.config.ts`의
exclude는 동기화되지 않은 상태였습니다.

- `vitest.config.ts`의 `coverage.exclude`에 `src/scripts/**` 추가 —
  codecov.yml과 동기화. 운영 스크립트를 단위 테스트 95%로 요구하는 것은
  합리적이지 않고, 실제 동작은 e2e의 `e2e:prepare`에서 검증됨.
- 같은 맥락으로 타입 전용 파일 `src/utils/cms-types.ts`도 exclude — v8
  provider가 0/0 라인으로 잡아 리포트 노이즈였음.
- `src/utils/s3.test.ts`에 `AWS_ENDPOINT_URL_S3`가 세팅됐을 때의 업로드
  경로를 커버하는 테스트 추가 — 53c7767에서 내가 추가한 MinIO endpoint
  분기를 명시적으로 검증.
- `.github/workflows/ci.yml`의 build/test/e2e 3개 job에서 `cp .env.example .env`
  제거 — 53c7767에서 `package.json`의 동일 명령은 제거했으나 CI workflow
  에는 잔존했음. test 잡은 `src/tests/setup.ts`, e2e 잡은 `.env.test`가
  env를 담당하므로 모두 안전.

결과: lines 99.43% / branches 97.47% / functions 99.25% / statements 99.43%.
모든 threshold(95/90/95/95) 통과. Vitest 692 tests pass.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 53c77676bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/prisma.ts
Comment on lines 23 to 25
const adapter = new PrismaPg({
connectionString: withDatabaseSslParams(databaseUrl),
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass computed SSL settings into PrismaPg adapter

DATABASE_SSL_REJECT_UNAUTHORIZED and the local-host detection are computed here, but the resulting ssl object is never passed to new PrismaPg(...). That means this new configuration path is a no-op, so deployments that rely on DATABASE_SSL_REJECT_UNAUTHORIZED=false (for self-signed/internal certs) will still use the adapter default TLS behavior and can fail to connect.

Useful? React with 👍 / 👎.

Comment thread src/e2e/fixtures/auth.ts
data: {
id: userId,
name: 'Test Admin',
email: 'e2e@stdev.kr',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Generate unique seeded admin email for retried E2E runs

This seed helper always inserts email: 'e2e@stdev.kr', but User.email is unique and CI enables Playwright retries. If the CRUD test fails after creating this user, a retry will attempt the same insert without cleanup and fail with a unique-constraint error before exercising the scenario, turning retries into deterministic false failures.

Useful? React with 👍 / 👎.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

직전 커밋 cb0b41d에서 build/test/e2e 3개 job의 `cp .env.example .env`를
모두 제거했으나, `pnpm build`의 Next.js page collection 단계가
`@/utils/prisma`의 `DATABASE_URL is required` 가드를 터뜨려 build와 e2e가
실패했습니다(test job은 `src/tests/setup.ts`가 env를 세팅해 영향 없음).

`.env.example`의 placeholder 대신 **`.env.test`의 실제 테스트 값**을
복사하도록 복구:

- `build` job: `pnpm install` 직후 `cp .env.test .env` 스텝 추가.
- `e2e` job: `pnpm test:e2e:install` 직후 `cp .env.test .env` 스텝 추가.
  `pnpm test:e2e`가 내부적으로 `pnpm build`를 실행하므로 build와 동일한
  이유로 필요.
- `test` job은 그대로 유지 — Vitest는 `.env`를 자동 로드하지 않고
  `src/tests/setup.ts`에서 env를 주입하므로 cp 불필요.

`.env.test`는 e2e용 dummy 값이라 build에 해가 없고, `.env.example`의
placeholder보다 실제 동작 환경에 가까워 의도도 더 선명합니다.
@sboh1214 sboh1214 merged commit df9389c into main May 12, 2026
7 checks passed
@sboh1214 sboh1214 deleted the feat@add-tests branch May 12, 2026 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant